package com.springboot.autoconfigure.oss.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.BucketInfo;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.PutObjectRequest;
import com.google.common.collect.Lists;
import com.springboot.autoconfigure.oss.config.AliyunOSSPropertis;
import com.springboot.autoconfigure.oss.config.MiniOSSPropertis;
import com.springboot.autoconfigure.oss.config.OssConfigPropertis;
import com.springboot.autoconfigure.oss.model.FileInfo;
import com.springboot.autoconfigure.oss.model.FileOssOperationStatus;
import com.springboot.autoconfigure.oss.model.FileUploadStatus;
import com.springboot.autoconfigure.oss.service.AbstractInitClientServer;
import com.springboot.autoconfigure.oss.service.OssApiService;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import org.springframework.beans.factory.InitializingBean;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;

public class MinioOssApiServiceImpl implements OssApiService<MiniOSSPropertis>, AbstractInitClientServer<MinioClient> {
    //文件名层级分隔符号
    private static final String SPLIT_PATH = "_";

    //URL 上传指定文件名前缀
    private static final String URL_UPLOAD_PREFIX = "UPLOAD-BY-URL";


    private MiniOSSPropertis miniOSSPropertis;
    private OssConfigPropertis ossConfigPropertis;
    private volatile MinioClient minioClient;
    private final Object lock = new Object();

    public MinioOssApiServiceImpl(MiniOSSPropertis miniOSSPropertis, OssConfigPropertis ossConfigPropertis) {
        this.miniOSSPropertis = miniOSSPropertis;
        this.ossConfigPropertis = ossConfigPropertis;
    }


    @Override
    public MinioClient getinit() {
        if (minioClient == null) {
            synchronized (lock) {
                if (minioClient == null) {
                    MinioClient minioClient = MinioClient.builder()
                            .endpoint(miniOSSPropertis.getEndPoint())
                            .region(miniOSSPropertis.getRegion())
                            .credentials(miniOSSPropertis.getUsername(), miniOSSPropertis.getPassword())
                            .build();
                    try {
                        BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
                                .bucket(miniOSSPropertis.getBucket()).build();
                        boolean existsFlag = minioClient.bucketExists(bucketExistsArgs);
                        if (!existsFlag) {
                            MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(miniOSSPropertis.getBucket()).build();
                            minioClient.makeBucket(makeBucketArgs);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return minioClient;

                }
            }
        }
        return minioClient;
    }

    /**
     * 生成文件名称
     *
     * @param file
     * @return
     */
    public String getFileName(File file) {
        String fileName = null;
        String extFileName = FileUtil.extName(file);
        if (StrUtil.isEmptyIfStr(extFileName)) {
            fileName = FileUtil.mainName(file) + SPLIT_PATH + getFileDate() + SPLIT_PATH + UUID.randomUUID();
        } else {
            fileName = FileUtil.mainName(file) + SPLIT_PATH + getFileDate() + SPLIT_PATH + UUID.randomUUID() + "." + extFileName;
        }
        //指定的路径上传
        if (!StrUtil.isEmptyIfStr(ossConfigPropertis.getFolderPathName())) {
            fileName = ossConfigPropertis.getFolderPathName() + fileName;
        }
        return fileName;
    }

    private String getFileDate() {
        return DatePattern.PURE_DATETIME_MS_FORMAT.format(new Date());
    }

    public String getFileName(URL url) {
        return URL_UPLOAD_PREFIX + SPLIT_PATH + getFileDate() + SPLIT_PATH + UUID.randomUUID();
    }


    @Override
    public FileUploadStatus uploadFile(URL url) {
        return null;
    }

    @Override
    public FileUploadStatus uploadFile(URL url, String filePrix) {
        return null;
    }

    @Override
    public FileUploadStatus uploadFile(File file) {
        MinioClient minioClient = getinit();
        UploadObjectArgs uploadObjectArgs = null;
        String object = getFileName(file);
        try {
            uploadObjectArgs = UploadObjectArgs.builder()
                    .bucket(miniOSSPropertis.getBucket())
                    .object(object) //  上传后的文件名
                    .filename(file.getAbsolutePath()) // 本地文件路径
                    .build();
        } catch (IOException e) {
            e.printStackTrace();
            return FileUploadStatus.fail();
        }
        try {
            minioClient.uploadObject(uploadObjectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return FileUploadStatus.fail();
        }
        FileUploadStatus suceess = FileUploadStatus.suceess();
        suceess.setFileKey(getFileName(file));
        suceess.setUrl(this.findFile(object).stream().findFirst().orElse(""));
        return suceess;
    }


    @Override
    public List<FileInfo> getBucketSpaceFile(String prefix, int limit) {
        return null;
    }

    @Override
    public FileUploadStatus uploadAbsoulteFilePath(File file, String filePath) {
        MinioClient getinit = getinit();
        FileUploadStatus suceess = FileUploadStatus.suceess();
        return suceess;
    }

    @Override
    public FileUploadStatus uploadFile(File file, String fileName) {
        return null;
    }

    @Override
    public FileUploadStatus uploadFileAndCallBack(File file, String callbackUrl) {
        return null;
    }

    @Override
    public List<String> findFile(String... fileNames) {
        MinioClient minioClient = getinit();
        if (CollectionUtil.isEmpty(Arrays.asList(fileNames))) {
            return null;
        }
        ArrayList<String> resultUrl = Lists.newArrayList();
        for (String fileName : fileNames) {
            GetPresignedObjectUrlArgs.Builder builder = GetPresignedObjectUrlArgs.builder()
                    .bucket(miniOSSPropertis.getBucket()).object(fileName).method(Method.GET);
            if (miniOSSPropertis.getExpiryTime() != null) {
                builder.expiry(miniOSSPropertis.getExpiryTime(), TimeUnit.HOURS);
            }
            GetPresignedObjectUrlArgs presignedObjectUrlArgs = builder.build();
            try {
                resultUrl.add(minioClient.getPresignedObjectUrl(presignedObjectUrlArgs));
            } catch (ServerException |
                    InsufficientDataException | ErrorResponseException |
                    IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) {
                throw new RuntimeException(e.getMessage());
            }
        }
        return resultUrl;
    }


    @Override
    public FileUploadStatus findFileByKey(String fileKey) {
        return null;
    }

    @Override
    public FileOssOperationStatus delFile(String... fileNames) {
        MinioClient minioClient = getinit();
        for (String key : fileNames) {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(miniOSSPropertis.getBucket()).object(key).build();
            try {
                minioClient.removeObject(removeObjectArgs);
            } catch (ServerException |
                    InsufficientDataException | ErrorResponseException |
                    IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) {
                FileOssOperationStatus fail = FileOssOperationStatus.fail(key);
                throw new RuntimeException(e.getMessage());
            }
        }
        return FileOssOperationStatus.suceess();
    }
}
